const fs = require('fs-extra');
const path = require('path');
const xlsx = require('node-xlsx');
const { Line, Point, Polygon, Vector } = require('./geometry.min.js');
const turf = require('@turf/turf');

/**
 * 构建分段墙体
 * @param {*} array
 * @returns
 */
function buildSegmentedWallList(array) {
	const result = [];

	for (let index = 0; index < array.length; index++) {
		if (index === array.length - 1) {
			break;
		}

		const [start, end] = [array[index], array[index + 1]];

		result.push([start, end]);
	}

	return result;
}

const getLine = (from, to, thickness, clockwise = true) => {
	const offset = thickness / 2;

	const normal = [...Vector.rotate(
		...Vector.normalize(...Vector.fromBothPoint(...from, ...to)),
		(clockwise ? 1 : -1) * Math.PI / 2
	)];
	const translation = [...Vector.multiply(...normal, offset)];

	return {
		normal,
		translation,
		vector: [...Point.translate(...from, ...translation), ...normal]
	};
};

/**
 * 获取房间信息
 * @param {*} floor
 * @returns
 */
const getRoomInfo = floor => {
	const { cornerList, wallList, roomList } = floor.drawing;
	const { roomList: roomListExtend } = floor;

	const infoList = roomList.map((room, roomIndex) => {
		const cwLineList = [];
		const ccwLineList = [];

		room.cornerList.forEach((corner, index) => {
			const fromIndex = corner;

			const toIndex = index < room.cornerList.length - 1
				? room.cornerList[index + 1]
				: room.cornerList[0];
			const from = cornerList[fromIndex];
			const to = cornerList[toIndex];

			const thickness = wallList.find(wall => {
				return wall[0] === fromIndex && wall[1] === toIndex
					|| wall[1] === fromIndex && wall[0] === toIndex;
			})[2];

			cwLineList.push(getLine(from, to, thickness));
			ccwLineList.push(getLine(from, to, thickness, false));
		});

		const getOriginList = lineList => {
			return lineList.map((line, index) => {
				const nextIndex = index < lineList.length - 1 ? index + 1 : 0;
				const nextLine = lineList[nextIndex];

				const origin = Line.intersectLine(...line.vector, ...nextLine.vector);

				return origin === null
					? [...Point.translate(
						...cornerList[room.cornerList[nextIndex]],
						...line.translation)]
					: [...origin];
			});
		};

		const cwOriginList = getOriginList(cwLineList);
		const ccwOriginList = getOriginList(ccwLineList);
		const cwArea = Polygon.area(...cwOriginList.flat());
		const ccwArea = Polygon.area(...ccwOriginList.flat());

		const roomCustomArea = Number(roomListExtend[roomIndex]?.customArea) || null;

		return cwArea < ccwArea
			? { originList: cwOriginList, area: cwArea, customArea: roomCustomArea * 1000 * 1000 || null }
			: { originList: ccwOriginList, area: ccwArea, customArea: roomCustomArea * 1000 * 1000 || null };
	});

	return infoList;
};

const getDrawingWallsByRoom = (roomIndex, floor) => {
	const { wallList, cornerList, roomList } = floor.drawing;
	const { wallList: wallExtend } = floor;
	const roomCornerList = roomList[roomIndex]?.cornerList;
	const wholeRoomCornerList = [...roomCornerList, roomCornerList[0]];
	const wallListInRoom = [];

	// 构建闭合的分段墙体数组
	const relateConnerList = buildSegmentedWallList(wholeRoomCornerList);

	for (const [i, wallItem] of wallList.entries()) {
		const [c1, c2] = wallItem;

		const wall = relateConnerList.find(item => {
			const [rc1, rc2] = item;

			return (rc1 === c1 && rc2 === c2) || (rc1 === c2 && rc2 === c1);
		});

		if (wall) {
			wallListInRoom.push({
				resourceIndex: i,
				wallCornerIndex: wallItem,
				thickness: wallItem[2],
				wallId: 'wall' + i,
				wallCorner: [cornerList[c1], cornerList[c2]],
				wallType: wallExtend[i]?.code
			});
		}
	}

	// 房间内包含的墙
	return wallListInRoom;
};

function simplifyPolygon(polygon) {
	// 简化多边形，去除冗余点
	const simplified = turf.simplify(polygon, { tolerance: 0.0001, highQuality: true });
	return simplified;
}

function removeCollinearPoints(polygon) {
	const coordinates = polygon.geometry.coordinates[0];
	const newCoordinates = [coordinates[0]]; // 保留第一个点

	for (let i = 1; i < coordinates.length - 1; i++) {
		const p1 = coordinates[i - 1];
		const p2 = coordinates[i];
		const p3 = coordinates[i + 1];

		// 计算向量
		const v1 = [p2[0] - p1[0], p2[1] - p1[1]];
		const v2 = [p3[0] - p2[0], p3[1] - p2[1]];

		// 计算叉积
		const crossProduct = v1[0] * v2[1] - v1[1] * v2[0];

		// 如果叉积不为0，则三点不在同一直线上
		if (crossProduct !== 0) {
			newCoordinates.push(p2);
		}
	}

	newCoordinates.push(coordinates[coordinates.length - 1]); // 保留最后一个点

	// 构建新的多边形
	const newPolygon = turf.polygon([newCoordinates]);
	return newPolygon;
}

function isRectangle(points) {
	const originalPolygon = turf.polygon([[...points, points[0]]]);
	const simplifiedPolygon = simplifyPolygon(originalPolygon);
	const cleanedPolygon = removeCollinearPoints(simplifiedPolygon);
	const coordinates = cleanedPolygon.geometry.coordinates[0];

	if (coordinates.length !== 5) {
		return false;
	}

	// 提取多边形的四个顶点
	const [p1, p2, p3, p4] = coordinates;
	const length1 = Point.distanceToPoint(...p1, ...p2);
	const length2 = Point.distanceToPoint(...p2, ...p3);
	const length3 = Point.distanceToPoint(...p3, ...p4);
	const length4 = Point.distanceToPoint(...p4, ...p1);

	const isParallelAndEqual1 = Math.abs(length1 - length3) < 0.001;
	const isParallelAndEqual2 = Math.abs(length2 - length4) < 0.001;

	if (!isParallelAndEqual1 || !isParallelAndEqual2) {
		return false;
	}

	return true;
}

function generateXLSX(dataList, targetPath, sheetName = 'sheet1') {
	const buffer = xlsx.build([{
		name: sheetName,
		data: dataList
	}]);

	const writableStream = fs.createWriteStream(targetPath);

	return new Promise((resolve, reject) => {
		let offset = 0;
		const chunkSize = 1024 * 5;

		function writeChunk() {
			if (offset < buffer.length) {
				const chunk = buffer.slice(offset, offset + chunkSize);

				writableStream.write(chunk, (err) => {
					if (err) {
						reject(err);
					} else {
						offset += chunkSize;

						writeChunk();
					}
				});
			} else {
				writableStream.end();

				resolve(dataList.length - 1);
			}
		}

		writeChunk();
	});
}

module.exports = {
	getLine,
	getRoomInfo,
	getDrawingWallsByRoom,
	isRectangle,
	generateXLSX
};